//
//  WDPDeviceInfoManager.m
//  WDLoan
//
//  Created by 邓乐 on 2017/3/23.
//  Copyright © 2017年 wanda. All rights reserved.
//

#import "WDPDeviceInfoManager.h"
#import <AdSupport/AdSupport.h>
#import <UIDevice+YYAdd.h>
#import <AFNetworkReachabilityManager.h>
#import<SystemConfiguration/CaptiveNetwork.h>
#import<SystemConfiguration/SystemConfiguration.h>
#import<CoreFoundation/CoreFoundation.h>
#import <CoreTelephony/CTCarrier.h>
#import <CoreTelephony/CTTelephonyNetworkInfo.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <mach/machine.h>
#include <sys/mount.h>
#import <ifaddrs.h>
#import <arpa/inet.h>
#import <net/if.h>
#import <resolv.h>
#import <netdb.h>
#import <netinet/ip.h>
#import <net/ethernet.h>
#import "EMCrypt.h"

#define MDNS_PORT 5353
#define QUERY_NAME "_apple-mobdev2._tcp.local"
#define DUMMY_MAC_ADDR @"02:00:00:00:00:00"

NSString * const WDPDeviceInfoManagerKey = @"wdp_get_all_apps";
NSString * const WDPDeviceInfoManagerWS = @"zY8JZby3XmvO+jrwKTfcwQRSYzuzTX8+";
NSString * const WDPDeviceInfoManagerDefaultWS = @"F+fCw2o24iNeLJtqBc9ARkzkXqe8+4cO";
NSString * const WDPDeviceInfoManagerAIApp = @"FqK9mURKZHHog+yhlmsOpRykojTfAd01TORep7z7hw4=";
NSString * const WDPDeviceInfoManagerLocalizedName = @"czFtDcAeNWG0sfr6VrhJEw==";

#define IOS_CELLULAR    @"pdp_ip0"
#define IOS_WIFI        @"en0"
#define IOS_VPN         @"utun0"
#define IP_ADDR_IPv4    @"ipv4"
#define IP_ADDR_IPv6    @"ipv6"

@interface WDPDeviceInfoManager()
{
    NSString* _deviceInfo;
    NSArray* _appsInfo;
}
@end
@implementation WDPDeviceInfoManager

static WDPDeviceInfoManager* __instance = nil;

+ (instancetype)sharedManager {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        __instance = [[WDPDeviceInfoManager alloc] init];
    });
    return __instance;
}

- (NSString*)getDeviceInfo {
    if (SAFE_STRING(_deviceInfo).length > 0) {
        return _deviceInfo;
    }
    NSString* result = nil;
    
    //NSString *deviceName;
    //    NSString *OSName;
    NSString *OSVersion;
    UIDevice *device = [UIDevice currentDevice];
    //deviceName = [device localizedModel];
    //    OSName = [device systemName];
    OSVersion = [device systemVersion];
    //    NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];
    NSString *appVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];
    //    NSString* bundleId = [[NSBundle mainBundle]bundleIdentifier];
    NSString* deviceInfo = [NSString stringWithFormat:@"%@", [WDPDeviceInfoManager deviceHardInfo]];
    NSNumber* root = [NSNumber numberWithBool:[WDPDeviceInfoManager isJailBreak]];
    NSString* proxyIpStr = [self proxyUrl];
    //ip
    NSString* ipAddresses = [WDPDeviceInfoManager getIPAddress:YES];
    CGRect screenRect = [UIScreen mainScreen ].bounds;
    //剩余电量
    //NSString* batteryLevelStr = [NSString stringWithFormat:@"%0f",[UIDevice currentDevice].batteryLevel*100.0];
    
    //idfa idfv
    NSString *idfaStr = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
    NSString *idfvStr = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
    
    //cpu核数
    //int cpuCount = countOfCores();
    
    //wifi name、mac
    NSString *wifiName = @"NotFound";
    NSString *wifiMac = @"NotFound";
    NSDictionary* wifiDict = [self checkWifiInfo];
    if (wifiDict) {
        wifiName = [wifiDict valueForKey:@"SSID"];
        wifiMac = [wifiDict valueForKey:@"BSSID"];
    }
    
//    //开机时间
//    NSString* deviceLaunchTime = [self getLaunchSystemTime];
//
//    //网络制式
//    CTTelephonyNetworkInfo* info = [[CTTelephonyNetworkInfo alloc] init];
//    NSString* simTechnologyInfo = [self checkNetworkTypeWithNetworkInfo:info];
//    NSString* cellularProviderInfo = [self checkCarrierWithNetworkInfo:info];
//    NSString* mncStr = [self mncInCarrier:[info subscriberCellularProvider]];
//    NSString* mccStr = [self mccInCarrier:[info subscriberCellularProvider]];
//    //NSString* isoStr = [self isoInCarrier:[info subscriberCellularProvider]];
//    NSString* accessTechnology = nil;
//
//    switch ([AFNetworkReachabilityManager sharedManager].networkReachabilityStatus) {
//        case AFNetworkReachabilityStatusReachableViaWiFi:
//            accessTechnology =  @"WIFI";
//            break;
//
//        case AFNetworkReachabilityStatusReachableViaWWAN:
//            accessTechnology = [simTechnologyInfo copy];
//            break;
//
//        default:
//            accessTechnology = @"UNKNOWN";
//            break;
//    }
    
//    NSArray* appLists = [self checkApp];
//
//    //app list
//    if (SAFE_STRING([[WDPNetworkConfig defaultManager] getToken]).length > 0 && (![[WDSDUserInfoDataModel sharedInstace].mobile isEqualToString:@"15355436031"])) {
//        //登陆过且手机号码非特殊的
//        if (_appsInfo.count > 0) {
//            appLists = _appsInfo;
//        }
////        appLists = [self getAppsInfo];
//    }
    //@"latitude":[NSString stringWithFormat:@"%lf",[WDPMapUtil defaultManager].latitude],
    //@"longitude":[NSString stringWithFormat:@"%lf",[WDPMapUtil defaultManager].longitude],
    NSDictionary* dict = @{
                           @"openUUID":[NSString deviceUUID],
                           @"osName": @"iOS",
                           @"osVersion": SAFE_STRING(OSVersion),
                           @"root": root,
                           @"appVersion": SAFE_STRING(appVersion),
                           @"model": SAFE_STRING(deviceInfo),
                           @"screen": [NSString stringWithFormat:@"%.0lf*%.0lf",screenRect.size.width,screenRect.size.height],
                           @"cpu":SAFE_STRING([WDPDeviceInfoManager getCPUType]),
                           @"memory":SAFE_STRING([WDPDeviceInfoManager getTotalMemorySize]),
                           @"capacity":SAFE_STRING([WDPDeviceInfoManager getTotalDiskSize]),
                           @"availableCapacity":SAFE_STRING([WDPDeviceInfoManager getAvailableDiskSize]),
                           @"wifiName":SAFE_STRING(wifiName),
                           @"wifiMac":SAFE_STRING(wifiMac),
                           @"IP":SAFE_STRING(ipAddresses),
                           @"proxyIp":SAFE_STRING(proxyIpStr),
                           @"idfa":SAFE_STRING(idfaStr),
                           @"idfv":SAFE_STRING(idfvStr)
                           };
    
    /*
     NSDictionary* dict = @{@"mobile":SAFE_STRING([WDSDUserInfoDataModel sharedInstace].mobile),
                           @"openUUID":[NSString deviceUUID],
                           @"osName": @"iOS",
                           @"osVersion": SAFE_STRING(OSVersion),
                           @"root": root,
                           @"appVersion": SAFE_STRING(appVersion),
                           @"model": SAFE_STRING(deviceInfo),
                           @"screen": [NSString stringWithFormat:@"%.0lf*%.0lf",screenRect.size.width,screenRect.size.height],
                           @"cpu":SAFE_STRING([WDPDeviceInfoManager getCPUType]),
                           @"memory":SAFE_STRING([WDPDeviceInfoManager getTotalMemorySize]),
                           @"cellularProvider":cellularProviderInfo,
                           @"simTechnology":simTechnologyInfo,
                           @"accessTechnology":accessTechnology,
                           @"capacity":SAFE_STRING([WDPDeviceInfoManager getTotalDiskSize]),
                           @"availableCapacity":SAFE_STRING([WDPDeviceInfoManager getAvailableDiskSize]),
                           @"wifiName":SAFE_STRING(wifiName),
                           @"wifiMac":SAFE_STRING(wifiMac),
                           @"manfacture":@"Apple",
                           @"latitude":[NSString stringWithFormat:@"%lf",[WDPMapUtil defaultManager].latitude],
                           @"longitude":[NSString stringWithFormat:@"%lf",[WDPMapUtil defaultManager].longitude],
                           @"IP":SAFE_STRING(ipAddresses),
                           @"proxyIp":SAFE_STRING(proxyIpStr),
                           @"battery":SAFE_STRING(batteryLevelStr),
                           @"cpuCount":[NSString stringWithFormat:@"%d",cpuCount],
                           @"idfa":SAFE_STRING(idfaStr),
                           @"idfv":SAFE_STRING(idfvStr),
                           @"appUtm":@"AppStore",
                           @"mnc":SAFE_STRING(mncStr),
                           @"mcc":SAFE_STRING(mccStr),
                           @"appList":appLists?appLists:[NSNull null],
                           @"deviceLaunchTime":SAFE_STRING(deviceLaunchTime),
                           @"appLaunchTime":SAFE_STRING(appLaunchTime)
                           };
     */
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:nil];
    NSString *jsonString =[[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    _deviceInfo = jsonString;
    return result;
}

+ (NSString *)deviceHardInfo
{
    static NSString* _wdp_device_hard_info = nil;
    if (_wdp_device_hard_info == nil) {
        _wdp_device_hard_info = [self platform];
    }
    if (SAFE_STRING(_wdp_device_hard_info).length <= 0) {
        _wdp_device_hard_info = @"unknow";
    }
    return _wdp_device_hard_info;
}

+ (BOOL)isJailBreak
{
    static int flag = -1;
    static BOOL jailbroken = NO;
    if (flag != -1) {
        return jailbroken;
    }
    
    //无须频繁检测越狱。
    flag = 0;
    NSString *cydiaPath = @"/Applications/Cydia.app";
    NSString *aptPath = @"/private/var/lib/apt/";
    if ([[NSFileManager defaultManager] fileExistsAtPath:cydiaPath]) {
        jailbroken = YES;
    }
    if ([[NSFileManager defaultManager] fileExistsAtPath:aptPath]) {
        jailbroken = YES;
    }
    return jailbroken;
}

#pragma mark - getwifimac
- (NSString *)getWifiMac{
    NSString *wifiMac = nil;
    NSDictionary* wifiDict = [self checkWifiInfo];
    if (wifiDict) {
        
        wifiMac = [wifiDict valueForKey:@"BSSID"];
    }
    return wifiMac;
}
- (NSString *)getWifiName{
    
    NSString *wifiName = nil;
    NSDictionary* wifiDict = [self checkWifiInfo];
    if (wifiDict) {
        
        wifiName = [wifiDict valueForKey:@"SSID"];
    }
    return wifiName;
}
/*
 *screeen size*
 */
//- (NSString *)getScreenSize{
//
//    NSString *size = nil;
//    if (SCREEN_IS_480_HEIGHT){
//        size = @"3.5 in";
//    }
//    else if (SCREEN_IS_568_HEIGHT){
//        size = @"4.0 in";
//    }
//    else if (SCREEN_IS_667_HEIGHT){
//        size = @"4.7 in";
//    }
//    else if (SCREEN_IS_736_HEIGHT){
//        size = @"5.5 in";
//    }
//    else if (SCREEN_IS_812_HEIGHT){
//        size = @"5.8 in";
//    }
//    return size;
//}
         
 #pragma mark sysctlbyname utils
 + (NSString *)getSysInfoByName:(char *)typeSpecifier
 {
     size_t size;
     sysctlbyname(typeSpecifier, NULL, &size, NULL, 0);
     
     char *answer = malloc(size);
     sysctlbyname(typeSpecifier, answer, &size, NULL, 0);
     
     NSString *results = [NSString stringWithCString:answer encoding: NSUTF8StringEncoding];
     
     free(answer);
     return results;
 }

 + (NSString *)platform
 {
     return [self getSysInfoByName:"hw.machine"];
 }


 // Thanks, Tom Harrington (Atomicbird)
 + (NSString *)hwmodel
 {
     return [self getSysInfoByName:"hw.model"];
 }
         
#pragma mark- get info
- (NSDictionary*)checkWifiInfo {
    static NSDictionary *dict = nil;
    if (dict != nil) {
        return dict;
    }
    CFArrayRef myArray = CNCopySupportedInterfaces();
    if (myArray != NULL) {
        CFDictionaryRef myDict =CNCopyCurrentNetworkInfo(CFArrayGetValueAtIndex(myArray, 0));
        if (myDict != NULL) {
            dict = (NSDictionary*)CFBridgingRelease(myDict);
        }
        CFRelease(myArray);
    }
    return dict;
}

- (NSString*)mncInCarrier:(CTCarrier *)carrier {
    NSString *ret = @"UNKNOWN";
    if (carrier == nil) {
        return ret;
    }
    
    return [carrier mobileNetworkCode];
}

- (NSString*)mccInCarrier:(CTCarrier *)carrier {
    NSString *ret = @"UNKNOWN";
    if (carrier == nil) {
        return ret;
    }
    
    return [carrier mobileCountryCode];
}

- (NSString*)isoInCarrier:(CTCarrier *)carrier {
    NSString *ret = @"UNKNOWN";
    if (carrier == nil) {
        return ret;
    }
    
    return [carrier isoCountryCode];
}

- (NSString*)carrierNameInCarrier:(CTCarrier *)carrier {
    NSString *ret = @"UNKNOWN";
    if (carrier == nil) {
        return ret;
    }
    
    return [carrier carrierName];
}

/*
 *IMSI(International Mobile Subscriber Identification Number,国际移动用户识别码)：是区别移动用户的标志，储存在SIM卡中，可用于区别移动用户的有效信息。其总长度不超过15位，同样使用0～9的数字。其中MCC是移动用户所属国家代号，占3位数字，中国的MCC规定为460；MNC是移动网号码，最多由两位数字组成，用于识别移动用户所归属的移动通信网；MSIN是移动用户识别码，用以识别某一移动通信网中的移动用户
 */
- (NSString *)getIMSI{
    CTTelephonyNetworkInfo* info = [[CTTelephonyNetworkInfo alloc] init];

    CTCarrier *carrier = [info subscriberCellularProvider];
    NSString *mcc = [carrier mobileCountryCode];
    NSString *mnc = [carrier mobileNetworkCode];
    NSString *imsi = [NSString stringWithFormat:@"%@%@", SAFE_STRING(mcc), SAFE_STRING(mnc)];
    
    return imsi;

}
/**
 设备所使用网络的运营商
 参考network code wiki:https://en.wikipedia.org/wiki/Mobile_country_code#China_-_CN
 @return name
 */
- (NSString *)checkCarrierWithNetworkInfo:(CTTelephonyNetworkInfo*)info
{
    CTCarrier *carrier = [info subscriberCellularProvider];
    NSString *ret = @"";
    if (carrier == nil) {
        return ret;
    }
    NSString *code = [carrier mobileNetworkCode];
    if ([code isEqual:@""]) {
        return ret;
    } else if ([code isEqualToString:@"00"] || [code isEqualToString:@"02"] || [code isEqualToString:@"07"] || [code isEqualToString:@"08"]) {
        ret = @"China Mobile";
    } else if ([code isEqualToString:@"01"] || [code isEqualToString:@"06"] || [code isEqualToString:@"09"] ) {
        ret = @"China Unicom";
    } else if ([code isEqualToString:@"03"] || [code isEqualToString:@"05"] || [code isEqualToString:@"11"] ) {
        ret = @"China Telecom";
    } else if ([code isEqualToString:@"20"]) {
        ret = @"China Tietong";
    }
    return ret;
}


/**
 获取网络制式
 
 @param info <#info description#>
 @return <#return value description#>
 */
- (NSString*)checkNetworkTypeWithNetworkInfo:(CTTelephonyNetworkInfo*)info {
    
    NSString *currentRadioAccessTechnology = info.currentRadioAccessTechnology;
    NSString *strNetworkType = @"UNKNOWN";
    if (currentRadioAccessTechnology)
    {
        if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyGPRS]) {
            strNetworkType = @"GPRS";
        } else if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyEdge]) {
            strNetworkType = @"Edge";
        } else if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyWCDMA]) {
            strNetworkType = @"WCDMA";
        } else if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyHSDPA]) {
            strNetworkType = @"HSDPA";
        } else if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyHSUPA]) {
            strNetworkType = @"HSUPA";
        } else if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyCDMA1x]) {
            strNetworkType = @"CDMA1x";
        } else if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyCDMAEVDORev0]) {
            strNetworkType = @"CDMAEVDORev0";
        } else if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyCDMAEVDORevA]) {
            strNetworkType = @"CDMAEVDORevA";
        } else if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyCDMAEVDORevB]) {
            strNetworkType = @"CDMAEVDORevB";
        } else if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyeHRPD]) {
            strNetworkType = @"eHRPD";
        } else if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyLTE]) {
            strNetworkType = @"LTE";
        }
    }
    return strNetworkType;
}
         
+ (NSString*)getCPUType
{
    NSMutableString *cpu = [[NSMutableString alloc] init];
    size_t size;
    cpu_type_t type;
    cpu_subtype_t subtype;
    size = sizeof(type);
    sysctlbyname("hw.cputype", &type, &size, NULL, 0);
    
    size = sizeof(subtype);
    sysctlbyname("hw.cpusubtype", &subtype, &size, NULL, 0);
    
    // values for cputype and cpusubtype defined in mach/machine.h
    if (type == CPU_TYPE_I386) {
        [cpu appendString:@"i386"];
    } else if (type == CPU_TYPE_X86_64) {
        [cpu appendString:@"x86_64"];
    } else if (type == CPU_TYPE_X86) {
        [cpu appendString:@"x86"];
    } else if (type == CPU_TYPE_ARM) {
        [cpu appendString:@"arm"];
        switch(subtype)
        {
            case CPU_SUBTYPE_ARM_V6:
                [cpu appendString:@"v6"];
                break;
            case CPU_SUBTYPE_ARM_V7:
                [cpu appendString:@"v7"];
                break;
            case CPU_SUBTYPE_ARM_V7S:
                [cpu appendString:@"v7s"];
                break;
            case CPU_SUBTYPE_ARM_V8:
                [cpu appendString:@"V8"];
                break;
            default:
                [cpu appendFormat:@",subtype:%d",subtype];
                break;
        }
    } else if (type == CPU_TYPE_ARM64) {
        [cpu appendString:@"arm64"];
    } else {
        [cpu appendFormat:@"cputype:%d,subtype:%d",type,subtype];
    }
    
    return cpu;
}

//磁盘大小
+ (NSString *)fileSizeToString:(unsigned long long)fileSize
{
    //这里1024改成1000是广东的sb要求
    NSInteger KB = 1000;
    NSInteger MB = KB*KB;
    NSInteger GB = MB*KB;
    
    if (fileSize < 10)
    {
        return @"0 B";
        
    }else if (fileSize < KB)
    {
        return @"< 1 KB";
        
    }else if (fileSize < MB)
    {
        return [NSString stringWithFormat:@"%.1f KB",ceil(((CGFloat)fileSize)/KB)];
        
    }else if (fileSize < GB)
    {
        return [NSString stringWithFormat:@"%.1f MB",ceil(((CGFloat)fileSize)/MB)];
        
    }else
    {
        return [NSString stringWithFormat:@"%.1f GB",ceil(((CGFloat)fileSize)/GB)];
    }
}

//获取总内存大小
+ (NSString*)getTotalMemorySize
{
    return [WDPDeviceInfoManager fileSizeToString:[NSProcessInfo processInfo].physicalMemory];
}

//磁盘总量
+ (NSString*)getTotalDiskSize
{
    struct statfs buf;
    unsigned long long freeSpace = -1;
    if (statfs("/var", &buf) >= 0)
    {
        freeSpace = (unsigned long long)(buf.f_bsize * buf.f_blocks);
    }
    return [WDPDeviceInfoManager fileSizeToString:freeSpace];
}

//获取可用磁盘容量
+ (NSString*)getAvailableDiskSize
{
    struct statfs buf;
    unsigned long long freeSpace = -1;
    if (statfs("/var", &buf) >= 0)
    {
        freeSpace = (unsigned long long)(buf.f_bsize * buf.f_bavail);
    }
    return [WDPDeviceInfoManager fileSizeToString:freeSpace];
}

//获取ip
+ (NSString *)getIPAddress:(BOOL)preferIPv4
{
    NSString* result = nil;
    if (SAFE_STRING(result).length > 0) {
        return result;
    }
    NSArray *searchArray = preferIPv4 ?
    @[ IOS_VPN @"/" IP_ADDR_IPv4, IOS_VPN @"/" IP_ADDR_IPv6, IOS_WIFI @"/" IP_ADDR_IPv4, IOS_WIFI @"/" IP_ADDR_IPv6, IOS_CELLULAR @"/" IP_ADDR_IPv4, IOS_CELLULAR @"/" IP_ADDR_IPv6 ] :
    @[ IOS_VPN @"/" IP_ADDR_IPv6, IOS_VPN @"/" IP_ADDR_IPv4, IOS_WIFI @"/" IP_ADDR_IPv6, IOS_WIFI @"/" IP_ADDR_IPv4, IOS_CELLULAR @"/" IP_ADDR_IPv6, IOS_CELLULAR @"/" IP_ADDR_IPv4 ] ;
    
    NSDictionary *addresses = [self getIPAddresses];
    //DebugLog(@"addresses: %@", addresses);
    
    __block NSString *address;
    [searchArray enumerateObjectsUsingBlock:^(NSString *key, NSUInteger idx, BOOL *stop)
     {
         address = addresses[key];
         //筛选出IP地址格式
         if([self isValidatIP:address]) *stop = YES;
     } ];
    result = address ? address : @"0.0.0.0";
    return result;
}

+ (BOOL)isValidatIP:(NSString *)ipAddress {
    if (ipAddress.length == 0) {
        return NO;
    }
    NSString *urlRegEx = @"^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
    "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
    "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
    "([01]?\\d\\d?|2[0-4]\\d|25[0-5])$";
    
    NSError *error;
    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:urlRegEx options:0 error:&error];
    
    if (regex != nil) {
        NSTextCheckingResult *firstMatch=[regex firstMatchInString:ipAddress options:0 range:NSMakeRange(0, [ipAddress length])];
        
        if (firstMatch) {
            //NSRange resultRange = [firstMatch rangeAtIndex:0];
            //NSString *result=[ipAddress substringWithRange:resultRange];
            //输出结果
            //DebugLog(@"%@",result);
            return YES;
        }
    }
    return NO;
}

+ (NSDictionary *)getIPAddresses
{
    NSMutableDictionary *addresses = [NSMutableDictionary dictionaryWithCapacity:8];
    
    // retrieve the current interfaces - returns 0 on success
    struct ifaddrs *interfaces;
    if(!getifaddrs(&interfaces)) {
        // Loop through linked list of interfaces
        struct ifaddrs *interface;
        for(interface=interfaces; interface; interface=interface->ifa_next) {
            if(!(interface->ifa_flags & IFF_UP) /* || (interface->ifa_flags & IFF_LOOPBACK) */ ) {
                continue; // deeply nested code harder to read
            }
            const struct sockaddr_in *addr = (const struct sockaddr_in*)interface->ifa_addr;
            char addrBuf[ MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) ];
            if(addr && (addr->sin_family==AF_INET || addr->sin_family==AF_INET6)) {
                NSString *name = [NSString stringWithUTF8String:interface->ifa_name];
                NSString *type;
                if(addr->sin_family == AF_INET) {
                    if(inet_ntop(AF_INET, &addr->sin_addr, addrBuf, INET_ADDRSTRLEN)) {
                        type = IP_ADDR_IPv4;
                    }
                } else {
                    const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6*)interface->ifa_addr;
                    if(inet_ntop(AF_INET6, &addr6->sin6_addr, addrBuf, INET6_ADDRSTRLEN)) {
                        type = IP_ADDR_IPv6;
                    }
                }
                if(type) {
                    NSString *key = [NSString stringWithFormat:@"%@/%@", name, type];
                    addresses[key] = [NSString stringWithUTF8String:addrBuf];
                }
            }
        }
        // Free memory
        freeifaddrs(interfaces);
    }
    return [addresses count] ? addresses : nil;
}

unsigned int countOfCores()
{
    unsigned int ncpu;
    size_t len = sizeof(ncpu);
    sysctlbyname("hw.ncpu", &ncpu, &len, NULL, 0);
    
    return ncpu;
}

- (NSString *)proxyUrl
{
    static NSString* result = nil;
    if (SAFE_STRING(result).length > 0) {
        return result;
    }
    NSDictionary* proxyDict = (NSDictionary *)CFBridgingRelease(CFNetworkCopySystemProxySettings());
    
    if (proxyDict) {
        NSNumber* isHTTPEnable = [proxyDict objectForKey:(NSString *)CFBridgingRelease(kCFNetworkProxiesHTTPEnable)];
        NSNumber* isAutoConfigEnable = [proxyDict objectForKey:(NSString *)CFBridgingRelease(kCFNetworkProxiesProxyAutoConfigEnable)];
        
        if (isHTTPEnable.boolValue) {
            NSString* httpServer = [proxyDict objectForKey:(NSString *)CFBridgingRelease(kCFNetworkProxiesHTTPProxy)];
            NSNumber* httpPort = [proxyDict objectForKey:(NSString *)CFBridgingRelease(kCFNetworkProxiesHTTPPort)];
            result = [NSString stringWithFormat:@"%@:%zd",httpServer,httpPort.integerValue];
            return result;
        }
        
        if (isAutoConfigEnable.boolValue) {
            NSString* autoConfigUrl = [proxyDict objectForKey:(NSString *)CFBridgingRelease(kCFNetworkProxiesProxyAutoConfigURLString)];
            result = autoConfigUrl;
            return autoConfigUrl;
        }
    }
    return @"";
}

/**
 通过scheme检测是否安装某app

 @return @[@{@"appName":@"万达财富"},@{@"appName":@"万达贷"}];
 */
- (NSArray*)checkApp {
    
    NSArray* list = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"AppScheme" ofType:@"plist"]];
    
    if (list.count < 1) {
        return nil;
    }
    
    NSMutableArray *resultArray = [NSMutableArray array];
    [list enumerateObjectsUsingBlock:^(NSDictionary* obj, NSUInteger idx, BOOL * _Nonnull stop) {
        NSString* scheme = [obj objectForKey:@"scheme"];
        if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:scheme]]) {
            //have it
            if ([obj objectForKey:@"appName"]) {
                [resultArray addObject:@{@"appName":[obj objectForKey:@"appName"]}];
            }
        }
    }];
    return resultArray;
}

//统计安装信息
- (NSArray*)getAppsInfo {
    
    Class LSApplicationWorkspace_class = NSClassFromString([EMCrypt decryptUseDES:WDPDeviceInfoManagerWS key:WDPDeviceInfoManagerKey]);
    if (LSApplicationWorkspace_class == Nil) {
        return nil;
    }
    SEL defaultWorkspaceSelector = NSSelectorFromString([EMCrypt decryptUseDES:WDPDeviceInfoManagerDefaultWS key:WDPDeviceInfoManagerKey]);
    if (defaultWorkspaceSelector == NULL) {
        return nil;
    }
    
    if ([LSApplicationWorkspace_class respondsToSelector:defaultWorkspaceSelector]) {
        //get instance
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
        NSObject* workspace = [LSApplicationWorkspace_class performSelector:defaultWorkspaceSelector];
#pragma clang diagnostic pop
        if (workspace == nil) {
            return nil;
        }
        
        SEL allInstalledApplicationsSelector = NSSelectorFromString([EMCrypt decryptUseDES:WDPDeviceInfoManagerAIApp key:WDPDeviceInfoManagerKey]);
        if (allInstalledApplicationsSelector == NULL) {
            return nil;
        }
        
        if ([workspace respondsToSelector:allInstalledApplicationsSelector]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
            NSArray* apps = [workspace performSelector:allInstalledApplicationsSelector];
#pragma clang diagnostic pop
            if ([apps isKindOfClass:[NSArray class]] == NO) {
                return nil;
            }
            if (apps == nil || apps.count < 1) {
                return nil;
            }
            
            NSMutableArray* contentArray = [NSMutableArray arrayWithCapacity:apps.count];
            
            [apps enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
                SEL localNameSel = NSSelectorFromString([EMCrypt decryptUseDES:WDPDeviceInfoManagerLocalizedName key:WDPDeviceInfoManagerKey]);
                if (localNameSel == NULL) {
                    *stop = YES;
                }
                if ([obj respondsToSelector:localNameSel]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
                    NSString *name = [obj performSelector:localNameSel];
#pragma clang diagnostic pop
                    if (SAFE_STRING(name).length > 0) {
                         [contentArray addObject:@{@"appName":SAFE_STRING(name)}];
                    }
                   
                }
                
            }];
            return contentArray;
        }
    }
    
    return nil;
}

- (NSString*)getLaunchSystemTime {
    NSString* result = nil;
    int mib[2];
    size_t size;
    struct timeval  boottime;
    
    mib[0] = CTL_KERN;
    mib[1] = KERN_BOOTTIME;
    size = sizeof(boottime);
    if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 && boottime.tv_sec != 0)
    {
        // successful call
        NSDate* bootDate = [NSDate dateWithTimeIntervalSince1970:boottime.tv_sec];
        NSDateFormatter *format = [[NSDateFormatter alloc] init];
        format.dateFormat = @"yyyyMMddHHmmss";
        result = [format stringFromDate:bootDate];
    }
    
    return result;
}

- (NSString *)getNetworkStates {
    NSString* networkType = nil;
    
    AFNetworkReachabilityManager  *man=[AFNetworkReachabilityManager sharedManager];
    //开始监听
    [man startMonitoring];
    
    switch (man.networkReachabilityStatus) {
        case AFNetworkReachabilityStatusReachableViaWiFi:
            networkType =  @"WIFI";
            break;
            
        case AFNetworkReachabilityStatusReachableViaWWAN:
            networkType = [self networkStatus];
            break;
            
            
        default:
            networkType = @"unknow";
            break;
    }
    return networkType;
}

- (NSString*)networkStatus{
    NSString *netType = nil;
    
    NSArray *typeStrings2G = @[CTRadioAccessTechnologyEdge,
                               CTRadioAccessTechnologyGPRS,
                               CTRadioAccessTechnologyCDMA1x];
    
    NSArray *typeStrings3G = @[CTRadioAccessTechnologyHSDPA,
                               CTRadioAccessTechnologyWCDMA,
                               CTRadioAccessTechnologyHSUPA,
                               CTRadioAccessTechnologyCDMAEVDORev0,
                               CTRadioAccessTechnologyCDMAEVDORevA,
                               CTRadioAccessTechnologyCDMAEVDORevB,
                               CTRadioAccessTechnologyeHRPD];
    
    NSArray *typeStrings4G = @[CTRadioAccessTechnologyLTE];
    
    CTTelephonyNetworkInfo *teleInfo= [[CTTelephonyNetworkInfo alloc] init];
    NSString *accessString = teleInfo.currentRadioAccessTechnology;
    if ([typeStrings4G containsObject:accessString]) {
        netType = @"4G";
    } else if ([typeStrings3G containsObject:accessString]) {
        netType = @"3G";
    } else if ([typeStrings2G containsObject:accessString]) {
        netType = @"2G";
    } else {
        netType = @"未知网路";
    }
    return netType;
}

@end
